package tree;

import data.Table;
import node.Node;

import java.util.ArrayList;
import java.util.List;

/**
 * @author Yakiv Tymoshenko
 * @since 14.10.12
 */
public class Tree {

    public static Tree fromTable(Table table) {
        Tree tree = new Tree();
        initNodes(tree, table);
        setChildren(tree, table);
        setParents(tree);
        tree.setRoot(findRoot(tree));

        return tree;
    }

    private static void initNodes(Tree tree, Table table) {
        Node node;
        int index;
        Object key;
        for (String[] row : table.getData()) {
            index = Integer.valueOf(row[0]);
            key = row[1];
            node = new Node(index, key);
            tree.addNode(node);
        }
    }

    private static void setChildren(Tree tree, Table table) {
        Node node;
        String tmp;
        int index, left, right;
        for (String[] row : table.getData()) {
            index = Integer.valueOf(row[0]);
            tmp = row[2];
            left = tmp.equals("NIL") ? 0 : Integer.valueOf(tmp);
            tmp = row[3];
            right = tmp.equals("NIL") ? 0 : Integer.valueOf(tmp);
            node = tree.getNode(index);
            node.setLeft(tree.getNode(left));
            node.setRight(tree.getNode(right));
        }
    }

    private static void setParents(Tree tree) {
        Node leftChild, rightChild;
        for (Node n : tree.getNodes()) {
            leftChild = n.getLeft();
            setParent(leftChild, n);
            rightChild = n.getRight();
            setParent(rightChild, n);
        }
    }

    private static void setParent(Node child, Node parent) {
        if (child != null) {
            child.setParent(parent);
        }
    }

    private static Node findRoot(Tree tree) {
        Node root = null;
        for (Node node : tree.getNodes()) {
            if (node.getParent() == null) {
                root = node;
                break;
            }
        }
        return root;
    }

    private Node root;
    private List<Node> nodes;

    public Tree() {
        this(new ArrayList<Node>());
    }

    public Tree(List<Node> nodes) {
        this.nodes = nodes;
    }

    public void addNode(Node node) {
        nodes.add(node);
    }

    public Node getNode(int index) {
        Node result = null;
        for (Node node : nodes) {
            if (node.getIndex() == index) {
                result = node;
                break;
            }
        }
        return result;
    }

    public List<Node> getNodes() {
        return nodes;
    }

    public Node getRoot() {
        return root;
    }

    public void setRoot(Node root) {
        this.root = root;
    }
}
